#include <functional>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>

using namespace std;

void test1() {
  int value = 1;
  // auto copy_value = [value] { return value; };
  // auto copy_value = [=value] { return value; };
  auto copy_value = [&value] { return value; };
  value = 100;
  cout << copy_value() << endl;
}

void test2() {
  auto generic = [](auto x, auto y) { return x + y; };
  cout << generic(1, 2) << endl;
  cout << generic(1.0, 2) << endl;
}

using foo = void(int);
void test3_1(foo f) { f(1); }
void test3() {
  auto f = [](int val) { cout << val << endl; };
  test3_1(f);
  f(1);
}

int foo4(int val) { return val; }
void test4() {
  std::function<int(int)> func = foo4;
  int imp = 10;
  function<int(int)> func2 = [&](int val) { return 1 + val + imp; };
  cout << func(10) << endl;
  cout << func2(10) << endl;
}

int foo5(int a, int b, int c) { return a + b + c; }
void test5() {
  auto bindFoo = std::bind(foo5, std::placeholders::_1, 1, 2);
  auto r = bindFoo(1);
  cout << r << endl;
}

void test6(string_view &&str) { cout << "rvalue" << endl; }
void test6(string_view &str) { cout << "lvalue" << endl; }
void test6_1() {
  string_view str("hello world");
  // test6(str);
  test6(std::move(str));
  const int &b = std::move(1);
  cout << b << endl;
}

void test7() {
  string str = "hello world";
  vector<string> v;
  v.push_back(str);
  v.push_back(std::move(str));
  cout << str << endl;
}

void test8(int &v) { cout << "lvalue" << endl; }
void test8(int &&v) { cout << "rvalue" << endl; }
void test8_1(int &&v) { test8(v); }
void test8_2() { test8_1(1); }

int main() { test8_2(); }